<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.3.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/images/logo.svg" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"chuangges.gitee.io","root":"/","scheme":"Pisces","version":"7.8.0","exturl":false,"sidebar":{"position":"right","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":true,"show_result":true,"style":"mac"},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="类型检查、高级类型、命名空间、声明合并、装饰器、JSX">
<meta property="og:type" content="article">
<meta property="og:title" content="TypeScript 进阶语法">
<meta property="og:url" content="https://chuangges.gitee.io/2019/11/06/11-2-typescript%20%E8%BF%9B%E9%98%B6%E8%AF%AD%E6%B3%95/index.html">
<meta property="og:site_name" content="闯哥要去流浪了">
<meta property="og:description" content="类型检查、高级类型、命名空间、声明合并、装饰器、JSX">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2019-11-06T08:06:20.000Z">
<meta property="article:modified_time" content="2023-09-19T12:02:07.028Z">
<meta property="article:author" content="chuangges">
<meta property="article:tag" content="JS 扩展">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://chuangges.gitee.io/2019/11/06/11-2-typescript%20%E8%BF%9B%E9%98%B6%E8%AF%AD%E6%B3%95/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>TypeScript 进阶语法 | 闯哥要去流浪了</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/atom.xml" title="闯哥要去流浪了" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">闯哥要去流浪了</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">愿你岁月可回首，且以深情共白头</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>
  <div class="reading-progress-bar"></div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://chuangges.gitee.io/2019/11/06/11-2-typescript%20%E8%BF%9B%E9%98%B6%E8%AF%AD%E6%B3%95/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/chuang.png">
      <meta itemprop="name" content="chuangges">
      <meta itemprop="description" content="chuangge's blog.">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="闯哥要去流浪了">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          TypeScript 进阶语法
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2019-11-06 16:06:20" itemprop="dateCreated datePublished" datetime="2019-11-06T16:06:20+08:00">2019-11-06</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2023-09-19 20:02:07" itemprop="dateModified" datetime="2023-09-19T20:02:07+08:00">2023-09-19</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/JS-%E6%89%A9%E5%B1%95/" itemprop="url" rel="index"><span itemprop="name">JS 扩展</span></a>
                </span>
            </span>

          <br>
            <span class="post-meta-item" title="本文字数">
              <span class="post-meta-item-icon">
                <i class="far fa-file-word"></i>
              </span>
                <span class="post-meta-item-text">本文字数：</span>
              <span>21k</span>
            </span>
            <span class="post-meta-item" title="阅读时长">
              <span class="post-meta-item-icon">
                <i class="far fa-clock"></i>
              </span>
                <span class="post-meta-item-text">阅读时长 &asymp;</span>
              <span>19 分钟</span>
            </span>
            <div class="post-description">类型检查、高级类型、命名空间、声明合并、装饰器、JSX</div>

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h1 id="一、类型检查"><a href="#一、类型检查" class="headerlink" title="一、类型检查"></a>一、类型检查</h1><h2 id="类型约束"><a href="#类型约束" class="headerlink" title="类型约束"></a>类型约束</h2><blockquote>
<p>类型约束对象为变量、函数的参数和返回值，比如字面量约束变量、void never 约束返回值。</p>
</blockquote>
  <figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 赋值后自动识别并约束 width 属性值为 number</span></span><br><span class="line"><span class="keyword">let</span> obj = &#123; <span class="attr">width</span>: <span class="number">200</span> &#125;;   </span><br><span class="line"></span><br><span class="line"><span class="comment">// name、必填, age 属性只读，其他属性可选</span></span><br><span class="line">type <span class="title class_">Person</span> = &#123;</span><br><span class="line">    <span class="attr">name</span>: string;</span><br><span class="line">    readonly <span class="attr">age</span>: number;</span><br><span class="line">    [<span class="attr">propName</span>: string]: string | number;</span><br><span class="line">&#125;; </span><br><span class="line"></span><br><span class="line"><span class="comment">// [自定义索引名: number]: 指定类型</span></span><br><span class="line">type <span class="title class_">MyArray1</span> = &#123; [<span class="attr">index</span>: number]: string &#125;;</span><br><span class="line">type <span class="title class_">MyArray2</span> = string[];</span><br><span class="line"><span class="keyword">let</span> <span class="attr">arr1</span>: <span class="title class_">MyArray1</span> = [<span class="string">&quot;a&quot;</span>, <span class="string">&quot;b&quot;</span>, <span class="string">&quot;c&quot;</span>];</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// Void：只能用于返回空值的函数</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">warnUser</span>(<span class="params"></span>):<span class="keyword">void</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;This is my warning message&quot;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 用户配置文件响应</span></span><br><span class="line">interface <span class="title class_">UserProfileResponse</span> &#123;</span><br><span class="line">    <span class="attr">id</span>: number;</span><br><span class="line">    <span class="attr">name</span>: string;</span><br><span class="line">    <span class="attr">email</span>: string;</span><br><span class="line">    <span class="attr">phone</span>: string;</span><br><span class="line">    <span class="attr">avatar</span>: string;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 登录响应</span></span><br><span class="line">interface <span class="title class_">LoginResponse</span> &#123;</span><br><span class="line">    <span class="attr">id</span>: number;</span><br><span class="line">    <span class="attr">name</span>: string;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 登录响应简写：不需要定义重复属性</span></span><br><span class="line">type <span class="title class_">LoginResponse</span> = <span class="title class_">Pick</span>&lt;<span class="title class_">UserProfileResponse</span>, <span class="string">&quot;id&quot;</span> | <span class="string">&quot;name&quot;</span>&gt;;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 内置的字符串操作类型</span></span><br><span class="line">type <span class="title class_">Role</span> = <span class="string">&quot;admin&quot;</span> | <span class="string">&quot;user&quot;</span>; </span><br><span class="line">type <span class="title class_">UppercaseRole</span> = <span class="title class_">Uppercase</span>&lt;<span class="title class_">Role</span>&gt;;        <span class="comment">// &quot;ADMIN&quot; | &quot;USER&quot;</span></span><br><span class="line">type <span class="title class_">LowercaseRole</span> = <span class="title class_">Lowercase</span>&lt;<span class="title class_">Role</span>&gt;;        <span class="comment">// &quot;admin&quot; | &quot;user&quot;</span></span><br><span class="line">type <span class="title class_">CapitalizeRole</span> = <span class="title class_">Capitalize</span>&lt;<span class="title class_">Role</span>&gt;;      <span class="comment">// &quot;Admin&quot; | &quot;User&quot;</span></span><br><span class="line">type <span class="title class_">UncapitalizeRole</span> = <span class="title class_">Uncapitalize</span>&lt;<span class="title class_">Role</span>&gt;;  <span class="comment">// &quot;admin&quot; | &quot;user&quot;</span></span><br></pre></td></tr></table></figure>

<h2 id="类型断言"><a href="#类型断言" class="headerlink" title="类型断言"></a>类型断言</h2><blockquote>
<p>用于指定一个值的类型而假设已经类型检查，只是在编译阶段时起作用。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 1、类型断言：&lt;类型&gt; 值、值 as 类型，注意使用 JSX 时只允许 as 语法。</span></span><br><span class="line"><span class="keyword">let</span> <span class="attr">val</span>: <span class="built_in">any</span> = <span class="string">&quot;hello&quot;</span>;</span><br><span class="line"><span class="keyword">let</span> <span class="attr">len_1</span>: <span class="built_in">number</span> = (&lt;<span class="built_in">string</span>&gt;val).<span class="property">length</span>;</span><br><span class="line"><span class="keyword">let</span> <span class="attr">len_2</span>: <span class="built_in">number</span> = (val <span class="keyword">as</span> <span class="built_in">string</span>).<span class="property">length</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、非空断言：无法断定类型时，操作符 ! 断言操作对象非 null、undefined</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">myFunc</span>(<span class="params">maybeString: <span class="built_in">string</span> | <span class="literal">undefined</span> | <span class="literal">null</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> <span class="attr">onlyString</span>: <span class="built_in">string</span> = maybeString;   <span class="comment">// Error</span></span><br><span class="line">    <span class="keyword">const</span> <span class="attr">ignoreUndefinedAndNull</span>: <span class="built_in">string</span> = maybeString!;  <span class="comment">// Ok</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">type</span> <span class="title class_">NumGenerator</span> = <span class="function">() =&gt;</span> <span class="built_in">number</span>;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">myFunc</span>(<span class="params">numGenerator: NumGenerator | <span class="literal">undefined</span></span>) &#123;</span><br><span class="line">    <span class="keyword">const</span> num1 = <span class="title function_">numGenerator</span>();    <span class="comment">// Error</span></span><br><span class="line">    <span class="keyword">const</span> num2 = numGenerator!();   <span class="comment">// OK</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="attr">a</span>: <span class="built_in">number</span> | <span class="literal">undefined</span> = <span class="literal">undefined</span>;</span><br><span class="line"><span class="keyword">const</span> <span class="attr">b</span>: <span class="built_in">number</span> = a!;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(b); </span><br><span class="line"><span class="comment">// 编译后</span></span><br><span class="line"><span class="keyword">const</span> a = <span class="literal">undefined</span>;</span><br><span class="line"><span class="keyword">const</span> b = a;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(b);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 3、确定赋值断言：实例属性和变量声明后面放置一个 ! 来声明属性会被明确赋值。</span></span><br><span class="line"><span class="keyword">let</span> x!: <span class="built_in">number</span>;</span><br><span class="line"><span class="title function_">initData</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="number">2</span> * x);   <span class="comment">// Ok</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">initData</span>(<span class="params"></span>) &#123; x = <span class="number">10</span>; &#125;</span><br></pre></td></tr></table></figure>


<h2 id="类型推断"><a href="#类型推断" class="headerlink" title="类型推断"></a>类型推断</h2><blockquote>
<p>没有明确指定变量的类型时，TS 会根据某些规则自动推断出类型，常见场景有：声明变量时没有指定类型、函数默认参数、函数返回值。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a;                 <span class="comment">// 推断为 any</span></span><br><span class="line"><span class="keyword">let</span> b = <span class="number">1</span>;             <span class="comment">// 推断为 number</span></span><br><span class="line"><span class="keyword">let</span> c = [];            <span class="comment">// 推断为由 any 类型构成的数组</span></span><br><span class="line"><span class="keyword">let</span> <span class="title function_">d</span> = (<span class="params">x=<span class="number">1</span></span>) =&gt; x+<span class="number">1</span>;  <span class="comment">// 函数默认参数被推断为 number，返回值也会被推断</span></span><br><span class="line"><span class="keyword">let</span> e = [<span class="number">1</span>, <span class="literal">null</span>];     <span class="comment">// 推断出兼容所有数据的类型：number、null 的联合类型</span></span><br><span class="line"></span><br><span class="line">a = <span class="string">&#x27;seven&#x27;</span>;</span><br><span class="line">a = <span class="number">7</span>;</span><br><span class="line">b = <span class="string">&#x27;3&#x27;</span>;  <span class="comment">// 报错</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 上下文类型：根据变量所在位置的上下文进行推论</span></span><br><span class="line"><span class="variable language_">window</span>.<span class="property">onmousedown</span> = <span class="keyword">function</span>(<span class="params">mouseEvent: <span class="built_in">any</span></span>) &#123;</span><br><span class="line">    <span class="comment">// 编译通过，如果不指定 mouseEvent 类型则会报错</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(mouseEvent.<span class="property">button</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// TS 推论有时不符合预期，可以通过类型断言进行覆盖。</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Foo</span>&#123; <span class="attr">bar</span>: <span class="built_in">number</span> &#125;</span><br><span class="line"><span class="keyword">let</span> <span class="attr">foo</span>: <span class="title class_">Foo</span> = &#123;&#125; <span class="keyword">as</span> <span class="title class_">Foo</span>;  <span class="comment">// 约定对象按照接口规范</span></span><br><span class="line">foo.<span class="property">bar</span> = <span class="number">1</span>;               <span class="comment">// 实现对象的具体定义</span></span><br></pre></td></tr></table></figure>


<h2 id="类型兼容"><a href="#类型兼容" class="headerlink" title="类型兼容"></a>类型兼容</h2><blockquote>
<p>允许存在公共成员的变量相互赋值，常用于代码的复用但增加了检查成本，基础规则如下：</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 1、结构类型之间：通过成员描述类型的类和接口等。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 类只兼容实例属性和实例方法。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 成员少的兼容成员多的。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Animal</span> &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="built_in">string</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span> &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="built_in">string</span>;</span><br><span class="line">    <span class="attr">age</span>: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Size</span> &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="built_in">number</span>;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">prop: <span class="built_in">number</span></span>) &#123; &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> <span class="attr">a</span>: <span class="title class_">Animal</span>;</span><br><span class="line"><span class="keyword">let</span> <span class="attr">s</span>: <span class="title class_">Size</span>;</span><br><span class="line"><span class="keyword">let</span> p = <span class="keyword">new</span> <span class="title class_">Person</span>();</span><br><span class="line">p = a;       <span class="comment">// 报错</span></span><br><span class="line">p = s;</span><br><span class="line">a = p;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 2、函数之间</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 参数多的兼容参数少的</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 返回值的类型必须相同并且是被包含</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 可选参数不兼容固定参数和剩余参数</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">let</span> <span class="title function_">x</span> = (<span class="params">a: <span class="built_in">number</span></span>) =&gt; <span class="number">0</span>;</span><br><span class="line"><span class="keyword">let</span> <span class="title function_">y</span> = (<span class="params">b: <span class="built_in">number</span>, s: <span class="built_in">string</span></span>) =&gt; <span class="number">0</span>;</span><br><span class="line">x = y;      <span class="comment">// 报错</span></span><br><span class="line">y = x;     </span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="title function_">x</span> = (<span class="params"></span>) =&gt; (&#123;<span class="attr">name</span>: <span class="string">&#x27;Alice&#x27;</span>&#125;);</span><br><span class="line"><span class="keyword">let</span> <span class="title function_">y</span> = (<span class="params"></span>) =&gt; (&#123;<span class="attr">name</span>: <span class="string">&#x27;Alice&#x27;</span>, <span class="attr">age</span>: <span class="number">20</span>&#125;);</span><br><span class="line">y = x;      <span class="comment">// 报错</span></span><br><span class="line">x = y;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="title function_">a</span> = (<span class="params">p1: <span class="built_in">number</span>, p2: <span class="built_in">number</span></span>) =&gt; &#123;&#125;;</span><br><span class="line"><span class="keyword">let</span> <span class="title function_">b</span> = (<span class="params">p1?: <span class="built_in">number</span>, p2?: <span class="built_in">number</span></span>) =&gt; &#123;&#125;;</span><br><span class="line"><span class="keyword">let</span> <span class="title function_">c</span> = (<span class="params">...args: <span class="built_in">number</span>[]</span>) =&gt; &#123;&#125;;</span><br><span class="line">b = a;      <span class="comment">// 报错</span></span><br><span class="line">a = b;</span><br><span class="line">a = c;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 3、枚举类型之间不兼容但可以和数字类型兼容</span></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">Status</span> &#123; <span class="title class_">Ready</span>, <span class="title class_">Waiting</span> &#125;;</span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">Color</span> &#123; <span class="title class_">Red</span>, <span class="title class_">Blue</span>, <span class="title class_">Green</span> &#125;;</span><br><span class="line"><span class="keyword">let</span> status = <span class="title class_">Status</span>.<span class="property">Ready</span>;</span><br><span class="line">status = <span class="title class_">Color</span>.<span class="property">Green</span>;        <span class="comment">// 报错</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 4、泛型</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 没有成员时与类型无关</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 含有成员时类型必须一致</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 没有指定类型时看作 any</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">NotEmpty</span>&lt;T&gt; &#123; </span><br><span class="line">    <span class="attr">data</span>: T;   <span class="comment">// 注释掉则正确</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> <span class="attr">x</span>: <span class="title class_">NotEmpty</span>&lt;<span class="built_in">number</span>&gt;;</span><br><span class="line"><span class="keyword">let</span> <span class="attr">y</span>: <span class="title class_">NotEmpty</span>&lt;<span class="built_in">string</span>&gt;;</span><br><span class="line">x = y;         <span class="comment">// 报错</span></span><br></pre></td></tr></table></figure>


<h2 id="类型保护"><a href="#类型保护" class="headerlink" title="类型保护"></a>类型保护</h2><blockquote>
<p>在运行时检查类型信息的表达式，用于确保在特定语句块中的类型符合预期而可以放心访问其属性和方法，实现方式主要有四种：<code>in 是否对象的属性或方法、typeof 判断基本类型、instanceof 是否类的实例、类型保护函数 自定义一个返回值为类型谓词的判断函数</code>。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Bird</span> &#123;</span><br><span class="line">    <span class="attr">fly</span>: <span class="built_in">boolean</span>;</span><br><span class="line">    <span class="attr">sing</span>: <span class="function">() =&gt;</span> &#123;&#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Dog</span> &#123;</span><br><span class="line">    <span class="attr">fly</span>: <span class="built_in">boolean</span>;</span><br><span class="line">    <span class="attr">bark</span>: <span class="function">() =&gt;</span> &#123;&#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">trainAnimal</span>(<span class="params">animal: Bird | Dog</span>)&#123;</span><br><span class="line">    <span class="comment">// 类型断言的方式</span></span><br><span class="line">    <span class="keyword">if</span> (animal.<span class="property">fly</span>) &#123;</span><br><span class="line">       (animal <span class="keyword">as</span> <span class="title class_">Bird</span>).<span class="title function_">sing</span>()</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">       (animal <span class="keyword">as</span> <span class="title class_">Dog</span>).<span class="title function_">bark</span>()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// in 语法做类型保护</span></span><br><span class="line">    <span class="keyword">if</span> (<span class="string">&#x27;sing&#x27;</span> <span class="keyword">in</span> animal) &#123;</span><br><span class="line">        animal.<span class="title function_">sing</span>()</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        animal.<span class="title function_">bark</span>()</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 类型保护函数：类型谓词为 param is Type</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">isNumber</span>(<span class="params">x: <span class="built_in">any</span></span>): x is <span class="built_in">number</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="keyword">typeof</span> x === <span class="string">&quot;number&quot;</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="类型别名"><a href="#类型别名" class="headerlink" title="类型别名"></a>类型别名</h2><blockquote>
<p>对已知的一些类型通过 type 定义新名字以避免重复。它和接口的区别如下：</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 类型别名不能使用 extends、implement。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 接口创建一个可在任意地方使用的新名字，类型别名并不创建。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 应用场景：无法通过接口描述一个类型而需要联合/元组类型时。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Name</span> = <span class="built_in">string</span>;</span><br><span class="line"><span class="keyword">type</span> <span class="title class_">NameResolver</span> = <span class="function">() =&gt;</span> <span class="built_in">string</span>;</span><br><span class="line"><span class="keyword">type</span> <span class="title class_">NameOrResolver</span> = <span class="title class_">Name</span> | <span class="title class_">NameResolver</span>;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getName</span>(<span class="params">n: NameOrResolver</span>): <span class="title class_">Name</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">typeof</span> n === <span class="string">&#x27;string&#x27;</span> ? n : <span class="title function_">n</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 泛型</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Container</span> &lt;T&gt; =  &#123;<span class="attr">value</span>: T&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 属性中引用</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Tree</span> &lt;T&gt; = &#123;</span><br><span class="line">    <span class="attr">value</span>: T;</span><br><span class="line">    <span class="attr">left</span>: <span class="title class_">Tree</span> &lt;T&gt;;   </span><br><span class="line">    <span class="attr">right</span>: <span class="title class_">Tree</span> &lt;T&gt;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 配合交叉类型使用</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">LinkedList</span> &lt;T&gt; = T &amp; &#123; <span class="attr">next</span>: <span class="title class_">LinkedList</span> &lt;T&gt; &#125;;</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Person</span> &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> <span class="attr">people</span>: <span class="title class_">LinkedList</span>&lt;<span class="title class_">Person</span>&gt;;</span><br><span class="line"><span class="keyword">var</span> s = people.<span class="property">name</span>;</span><br><span class="line"><span class="keyword">var</span> s = people.<span class="property">next</span>.<span class="property">name</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 报错：类型别名不能出现在声明右侧的任何地方</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Yikes</span> = <span class="title class_">Array</span>&lt;<span class="title class_">Yikes</span>&gt;;</span><br></pre></td></tr></table></figure>


<h1 id="二、高级类型"><a href="#二、高级类型" class="headerlink" title="二、高级类型"></a>二、高级类型</h1><h2 id="交叉类型"><a href="#交叉类型" class="headerlink" title="交叉类型"></a>交叉类型</h2><blockquote>
<p>通过 <code>&amp;</code> 获取多个类型的并集，与继承的区别是继承可以有自己的属性而交叉没有。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> extend&lt;T, U&gt;(<span class="attr">first</span>: T, <span class="attr">second</span>: U): T &amp; U &#123;</span><br><span class="line">    <span class="keyword">const</span> result = &lt;T &amp; U&gt;&#123;&#125;;</span><br><span class="line">    for (let id in first) &#123;</span><br><span class="line">        (&lt;T&gt;result)[id] = first[id];</span><br><span class="line">    &#125;</span><br><span class="line">    for (let id in second) &#123;</span><br><span class="line">        if (!result.hasOwnProperty(id)) &#123;</span><br><span class="line">            (&lt;U&gt;result)[id] = second[id];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    return result;</span><br><span class="line">&#125;</span><br><span class="line">// x 拥有了 a、b 属性</span><br><span class="line">const x = extend(&#123; a: &#x27;hello&#x27; &#125;, &#123; b: 42 &#125;);</span><br><span class="line">const a = x.a;</span><br><span class="line">const b = x.b;</span><br></pre></td></tr></table></figure>


<h2 id="联合类型"><a href="#联合类型" class="headerlink" title="联合类型"></a>联合类型</h2><blockquote>
<p>通过 <code>|</code> 获取多个类型中的一个，具体类型需要等到赋值时根据类型推论的规则推断出。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 类型限定</span></span><br><span class="line"><span class="keyword">let</span> <span class="attr">a</span>: <span class="built_in">number</span> | <span class="built_in">string</span> = <span class="string">&quot;a&quot;</span>;</span><br><span class="line"><span class="comment">// 取值限定</span></span><br><span class="line"><span class="keyword">let</span> <span class="attr">b</span>: <span class="string">&quot;a&quot;</span> | <span class="string">&quot;b&quot;</span> | <span class="string">&quot;c&quot;</span>;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fn</span>(<span class="params">name: <span class="built_in">string</span>, age: <span class="built_in">string</span> | <span class="built_in">number</span></span>)&#123; &#125;</span><br><span class="line"></span><br><span class="line">a = <span class="string">&#x27;hello&#x27;</span>;</span><br><span class="line">a = <span class="number">20</span>        <span class="comment">// 报错：已经推断出 string</span></span><br></pre></td></tr></table></figure>


<h2 id="索引类型"><a href="#索引类型" class="headerlink" title="索引类型"></a>索引类型</h2><blockquote>
<p>使用不存在的索引时会返回 undefined 而且没有约束，因此我们需要有对索引的约束。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123; <span class="attr">a</span>: <span class="number">1</span>, <span class="attr">b</span>: <span class="number">2</span>, <span class="attr">c</span>: <span class="number">3</span> &#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 不使用索引类型：</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getValue</span>(<span class="params">obj: <span class="built_in">any</span>,keys: <span class="built_in">string</span>[]</span>)&#123;</span><br><span class="line">    <span class="keyword">return</span> keys.<span class="title function_">map</span>(<span class="function"><span class="params">key</span> =&gt;</span> obj[key]);</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getValue</span>(obj,[<span class="string">&quot;c&quot;</span>,<span class="string">&quot;f&quot;</span>]))  <span class="comment">// 返回 undefined，没有约束</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用索引类型：T[k][] 表示返回值必须是 obj 中的值组成的列表</span></span><br><span class="line"><span class="keyword">function</span> getValue&lt;T,K <span class="keyword">extends</span> keyof T&gt;(<span class="attr">obj</span>: T, <span class="attr">keys</span>: K[]): T[K][] &#123; </span><br><span class="line">    <span class="keyword">return</span> keys.<span class="title function_">map</span>(<span class="function"><span class="params">key</span> =&gt;</span> obj[key]); <span class="comment">// keys 中的元素只能是 obj 中的键</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getValue</span>(obj,[<span class="string">&#x27;a&#x27;</span>, <span class="string">&#x27;b&#x27;</span>]));</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title function_">getValue</span>(obj,[<span class="string">&#x27;c&#x27;</span>, <span class="string">&#x27;f&#x27;</span>]));  <span class="comment">// 报错</span></span><br></pre></td></tr></table></figure>

<h2 id="映射类型"><a href="#映射类型" class="headerlink" title="映射类型"></a>映射类型</h2><blockquote>
<p>从旧类型中创建新类型的一种方式，比如将接口中的所有成员变成只读、可选。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">Obj</span>&#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="built_in">string</span>;</span><br><span class="line">    <span class="attr">b</span>: <span class="built_in">number</span>;</span><br><span class="line">    <span class="attr">c</span>: <span class="built_in">boolean</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将所有属性变为只读，生成一个新接口</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">ReadonlyObj</span> = <span class="title class_">Readonly</span>&lt;<span class="title class_">Obj</span>&gt;;</span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Readonly</span>&lt;T&gt; = &#123;</span><br><span class="line">    <span class="keyword">readonly</span> [P <span class="keyword">in</span> keyof T]: T[P];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 将所有属性变为可选</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">PartialObj</span> = <span class="title class_">Partial</span>&lt;<span class="title class_">Obj</span>&gt;;</span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Partial</span>&lt;T&gt; = &#123;</span><br><span class="line">    [P <span class="keyword">in</span> keyof T]?: T[P];</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 获取原类型的子集：两个等同</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">PickObj</span> = <span class="title class_">Pick</span>&lt;<span class="title class_">Obj</span>,<span class="string">&#x27;a&#x27;</span>|<span class="string">&#x27;b&#x27;</span>&gt;;</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">PickObj</span> &#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="built_in">string</span>,</span><br><span class="line">    <span class="attr">b</span>: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="条件类型"><a href="#条件类型" class="headerlink" title="条件类型"></a>条件类型</h2><blockquote>
<p>指由表达式所决定的类型，它使类型具有了不唯一性并增加了语言的灵活性。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 如果类型 T 可以被赋值给类型 U，name 结果就赋予 X 类型，否则赋予 Y 类型</span></span><br><span class="line">T <span class="keyword">extends</span> U ? X : Y;</span><br><span class="line"></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">TypeName</span>&lt;T&gt; =</span><br><span class="line">    T <span class="keyword">extends</span> <span class="built_in">string</span> ? <span class="built_in">string</span> :</span><br><span class="line">    T <span class="keyword">extends</span> <span class="built_in">number</span> ? <span class="built_in">number</span> :</span><br><span class="line">    T <span class="keyword">extends</span> <span class="built_in">boolean</span> ? <span class="built_in">boolean</span> :</span><br><span class="line">    T <span class="keyword">extends</span> <span class="literal">undefined</span> ? <span class="literal">undefined</span> :</span><br><span class="line">    T <span class="keyword">extends</span> <span class="title class_">Function</span> ? <span class="title class_">Function</span> :</span><br><span class="line">    <span class="built_in">object</span>;</span><br><span class="line"><span class="keyword">type</span> <span class="variable constant_">T1</span> = <span class="title class_">TypeName</span>&lt;<span class="built_in">string</span>&gt;;   <span class="comment">// 字符串类型</span></span><br><span class="line"><span class="keyword">type</span> <span class="variable constant_">T2</span> = <span class="title class_">TypeName</span>&lt;<span class="built_in">string</span>[]&gt;; <span class="comment">// object 类型</span></span><br><span class="line"><span class="keyword">type</span> <span class="variable constant_">T3</span> = <span class="title class_">TypeName</span>&lt;<span class="title class_">Function</span>&gt;; <span class="comment">// function 类型</span></span><br><span class="line"><span class="keyword">type</span> <span class="variable constant_">T4</span> = <span class="title class_">TypeName</span>&lt;<span class="built_in">string</span> | <span class="built_in">string</span>[]&gt;; <span class="comment">// string、obj 的联合类型</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 应用：类型的过滤</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Diff</span>&lt;T, U&gt; = T <span class="keyword">extends</span> U ? <span class="built_in">never</span> : T;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 作用是过滤掉第一个参数中的&#x27;a&#x27;。T5 为联合类型 &#x27;b&#x27; | &#x27;c&#x27; </span></span><br><span class="line"><span class="keyword">type</span> <span class="variable constant_">T5</span> = <span class="title class_">Diff</span>&lt; <span class="string">&#x27;a&#x27;</span>|<span class="string">&#x27;b&#x27;</span>|<span class="string">&#x27;c&#x27;</span>, <span class="string">&#x27;a&#x27;</span>|<span class="string">&#x27;e&#x27;</span> &gt;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 解析过程</span></span><br><span class="line"><span class="title class_">Diff</span>&lt;<span class="string">&#x27;a&#x27;</span>, <span class="string">&#x27;a&#x27;</span>|<span class="string">&#x27;e&#x27;</span>&gt; | <span class="title class_">Diff</span>&lt;<span class="string">&#x27;b&#x27;</span>, <span class="string">&#x27;a&#x27;</span>|<span class="string">&#x27;e&#x27;</span>&gt; | <span class="title class_">Diff</span>&lt;<span class="string">&#x27;c&#x27;</span>, <span class="string">&#x27;a&#x27;</span>|<span class="string">&#x27;e&#x27;</span>&gt;</span><br><span class="line"><span class="built_in">never</span> | <span class="string">&#x27;b&#x27;</span> | <span class="string">&#x27;c&#x27;</span></span><br><span class="line"><span class="string">&#x27;b&#x27;</span> | <span class="string">&#x27;c&#x27;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 内置方法</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> Exclude&lt;T, U&gt;：从 T 中剔除可以赋值给 U 的类型。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> Extract&lt;T, U&gt;：提取 T 中可以赋值给 U 的类型。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> NonNullable&lt;T&gt;：从 T 中剔除 null、undefined。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> InstanceType&lt;T&gt;：获取构造函数类型的实例类型。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> ReturnType&lt;T&gt;：获取函数返回值类型。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="comment">// &quot;b&quot; | &quot;d&quot;</span></span><br><span class="line"><span class="keyword">type</span> <span class="variable constant_">T0</span> = <span class="title class_">Exclude</span>&lt;<span class="string">&quot;a&quot;</span> | <span class="string">&quot;b&quot;</span> | <span class="string">&quot;c&quot;</span> | <span class="string">&quot;d&quot;</span>, <span class="string">&quot;a&quot;</span> | <span class="string">&quot;c&quot;</span> | <span class="string">&quot;f&quot;</span>&gt;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// &quot;a&quot; | &quot;c&quot;</span></span><br><span class="line"><span class="keyword">type</span> <span class="variable constant_">T1</span> = <span class="title class_">Extract</span>&lt;<span class="string">&quot;a&quot;</span> | <span class="string">&quot;b&quot;</span> | <span class="string">&quot;c&quot;</span> | <span class="string">&quot;d&quot;</span>, <span class="string">&quot;a&quot;</span> | <span class="string">&quot;c&quot;</span> | <span class="string">&quot;f&quot;</span>&gt;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// string | number</span></span><br><span class="line"><span class="keyword">type</span> <span class="variable constant_">T3</span> = <span class="title class_">NonNullable</span>&lt;<span class="built_in">string</span> | <span class="built_in">number</span> | <span class="literal">undefined</span>&gt;;</span><br></pre></td></tr></table></figure>


<h2 id="可为-null-的类型"><a href="#可为-null-的类型" class="headerlink" title="可为 null 的类型"></a>可为 null 的类型</h2><blockquote>
<p>TS 有两种特殊的类型 <code>null、undefined</code>，类型检查器默认它们可以赋值给任意类型。<code>--strictNullChecks</code> 标记可以解决此错误：当声明一个变量时，它不会自动包含 null、undefined，但是可以使用联合类型明确的包含它们：</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> s = <span class="string">&#x27;foo&#x27;</span>;</span><br><span class="line">s = <span class="literal">null</span>;        <span class="comment">// 报错</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="attr">sn</span>: <span class="built_in">string</span> | <span class="literal">null</span> = <span class="string">&#x27;bar&#x27;</span>;</span><br><span class="line">sn = <span class="literal">null</span>;       <span class="comment">// 正确</span></span><br><span class="line">sn = <span class="literal">undefined</span>;  <span class="comment">// 报错</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 可选参数/属性：使用 strictNullChecks 标记后默认添加 | undefined。</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">f</span>(<span class="params">x:<span class="built_in">number</span>, y?: <span class="built_in">number</span></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> x + (y || <span class="number">0</span>);</span><br><span class="line">&#125;</span><br><span class="line"><span class="title function_">f</span>(<span class="number">1</span>, <span class="literal">undefined</span>);</span><br><span class="line"><span class="title function_">f</span>(<span class="number">1</span>, <span class="literal">null</span>)  <span class="comment">// 报错</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">C</span> &#123;</span><br><span class="line">    <span class="attr">a</span>: <span class="built_in">number</span>;</span><br><span class="line">    b?: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> c = <span class="keyword">new</span> <span class="title function_">C</span>();</span><br><span class="line">c.<span class="property">a</span> = <span class="literal">undefined</span>;   <span class="comment">// 报错</span></span><br><span class="line">c.<span class="property">b</span> = <span class="literal">undefined</span>;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 类型保护去除 null</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">f</span>(<span class="params">sn: <span class="built_in">string</span> | <span class="literal">null</span></span>): <span class="built_in">string</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> sn || <span class="string">&quot;default&quot;</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 类型断言去除 null/undefined：去掉 ! 就会报错</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">fixed</span>(<span class="params">name: <span class="built_in">string</span> | <span class="literal">null</span></span>): <span class="built_in">string</span> &#123;</span><br><span class="line">    <span class="keyword">function</span> <span class="title function_">postfix</span>(<span class="params">epithet: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> name!.<span class="title function_">charAt</span>(<span class="number">0</span>) + <span class="string">&#x27;.  the &#x27;</span> + epithet;</span><br><span class="line">    &#125;</span><br><span class="line">    name = name || <span class="string">&quot;Bob&quot;</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="title function_">postfix</span>(<span class="string">&quot;great&quot;</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="字面量类型"><a href="#字面量类型" class="headerlink" title="字面量类型"></a>字面量类型</h2><blockquote>
<p>分为字符串、数字字面量类型，通过指定一个固定值实现类型约束或区分函数重载。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="attr">gender</span>: <span class="string">&quot;男&quot;</span>| <span class="string">&quot;女&quot;</span>;   <span class="comment">// 只能为是男或女</span></span><br><span class="line"><span class="keyword">let</span> <span class="attr">a</span>:<span class="string">&quot;A&quot;</span>;               <span class="comment">// 只能为 A</span></span><br><span class="line"><span class="keyword">let</span> <span class="attr">user</span>: &#123;              <span class="comment">// 必须有 name、age</span></span><br><span class="line">    <span class="attr">name</span>: <span class="built_in">string</span>,</span><br><span class="line">    <span class="attr">age</span>: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> <span class="attr">b</span>:<span class="number">1</span>;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">getNum</span>(<span class="params"></span>): <span class="number">1</span> | <span class="number">2</span> | <span class="number">3</span> | <span class="number">4</span> &#123; &#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 区分函数重载</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">createElement</span>(<span class="params">tagName: <span class="string">&quot;img&quot;</span></span>): <span class="title class_">HTMLImageElement</span>;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">createElement</span>(<span class="params">tagName: <span class="string">&quot;input&quot;</span></span>): <span class="title class_">HTMLInputElement</span>;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">createElement</span>(<span class="params">tagName: <span class="built_in">string</span></span>): <span class="title class_">Element</span> &#123; &#125;</span><br></pre></td></tr></table></figure>


<h2 id="可辨识联合"><a href="#可辨识联合" class="headerlink" title="可辨识联合"></a>可辨识联合</h2><blockquote>
<p>通过合并单例类型、联合类型、类型保护和类型别名创建的一个高级模式，也称为标签联合、代数数据类型，常用于在函数式编程。<code>实现要素</code>：具有单例类型属性作为可辨识特征、一个类型别名包含了哪些类型的联合、属性上有类型保护。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 将要联合的接口：都有 kind 属性但有不同的字符串字面量类型。</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Square</span> &#123;</span><br><span class="line">    <span class="attr">kind</span>: <span class="string">&quot;square&quot;</span>;</span><br><span class="line">    <span class="attr">size</span>: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Rectangle</span> &#123;</span><br><span class="line">    <span class="attr">kind</span>: <span class="string">&quot;rectangle&quot;</span>;</span><br><span class="line">    <span class="attr">width</span>: <span class="built_in">number</span>;</span><br><span class="line">    <span class="attr">height</span>: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Circle</span> &#123;</span><br><span class="line">    <span class="attr">kind</span>: <span class="string">&quot;circle&quot;</span>;</span><br><span class="line">    <span class="attr">radius</span>: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用可辨识联合：没有处理 case triangle 而会报错</span></span><br><span class="line"><span class="keyword">type</span> <span class="title class_">Shape</span> = <span class="title class_">Rectangle</span> | <span class="title class_">Circle</span> | triangle;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">area</span>(<span class="params">s: Shape</span>) &#123;</span><br><span class="line">    <span class="keyword">switch</span> (s.<span class="property">kind</span>) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;rectangle&#x27;</span>: <span class="keyword">return</span> s.<span class="property">height</span> * s.<span class="property">width</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;circle&#x27;</span>: <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="property">PI</span> * s.<span class="property">radius</span> ** <span class="number">2</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 完整性检查：没有涵盖所有可辨识联合的变化时让编译器通知。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 法一：启用 --strictNullChecks 并指定一个返回值类型。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 法二：使用 never 类型，用来除去所有可能情况后剩下的类型。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">area</span>(<span class="params">s: Shape</span>) &#123;</span><br><span class="line">    <span class="keyword">switch</span> (s.<span class="property">kind</span>) &#123;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;square&#x27;</span>: <span class="keyword">return</span> s.<span class="property">size</span> * s.<span class="property">size</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;rectangle&#x27;</span>: <span class="keyword">return</span> s.<span class="property">height</span> * s.<span class="property">width</span>;</span><br><span class="line">        <span class="keyword">case</span> <span class="string">&#x27;circle&#x27;</span>: <span class="keyword">return</span> <span class="title class_">Math</span>.<span class="property">PI</span> * s.<span class="property">radius</span> ** <span class="number">2</span>;</span><br><span class="line">        <span class="attr">default</span>: <span class="keyword">return</span> <span class="title function_">assertNever</span>(s);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">assertNever</span>(<span class="params">x: <span class="built_in">never</span></span>): <span class="built_in">never</span> &#123;</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;Unexpected object: &quot;</span> + x);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="多态的-this-类型"><a href="#多态的-this-类型" class="headerlink" title="多态的 this 类型"></a>多态的 this 类型</h2><blockquote>
<p>表示某个包含类或接口的子类型，称为 <code>F-bounded 多态性</code>，方便表现连贯接口间的继承。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">BasicCalculator</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">constructor</span>(<span class="params"><span class="keyword">protected</span> value: <span class="built_in">number</span> = <span class="number">0</span></span>) &#123; &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">curVal</span>(): <span class="built_in">number</span> &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">value</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">addVal</span>(<span class="attr">operand</span>: <span class="built_in">number</span>): <span class="variable language_">this</span> &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">value</span> += operand;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">multiply</span>(<span class="attr">operand</span>: <span class="built_in">number</span>): <span class="variable language_">this</span> &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">value</span> *= operand;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> v = <span class="keyword">new</span> <span class="title class_">BasicCalculator</span>(<span class="number">2</span>).<span class="title function_">multiply</span>(<span class="number">5</span>).<span class="title function_">addVal</span>(<span class="number">1</span>).<span class="title function_">curVal</span>();</span><br></pre></td></tr></table></figure>


<h1 id="三、命名空间"><a href="#三、命名空间" class="headerlink" title="三、命名空间"></a>三、命名空间</h1>  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 1、命名空间的单文件</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> namespace 声明的全局对象，主要用于组织代码并避免命名冲突。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 通过三斜线指令将额外变量引入到当前作用域，相当于源码嵌入。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 本质是 IIFE，不存在文件即模块的加载机制约束，不建议使用。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Page</span> &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">interface</span> <span class="title class_">IPage</span> &#123;</span><br><span class="line">        <span class="title function_">render</span>(<span class="attr">data</span>: <span class="built_in">object</span>): <span class="built_in">string</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">IndexPage</span> <span class="keyword">implements</span> <span class="title class_">IPage</span> &#123;</span><br><span class="line">        <span class="title function_">render</span>(<span class="attr">data</span>: <span class="built_in">object</span>): <span class="built_in">string</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&#x27;&lt;div&gt;Index page content&lt;/div&gt;&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 使用别名：import a = x.y</span></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Shapes</span> &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">namespace</span> <span class="title class_">Polygons</span> &#123;</span><br><span class="line">        <span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">Triangle</span> &#123; &#125;</span><br><span class="line">        <span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">Square</span> &#123; &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">import</span> polygons = <span class="title class_">Shapes</span>.<span class="property">Polygons</span>;</span><br><span class="line"><span class="keyword">let</span> sq = <span class="keyword">new</span> polygons.<span class="title class_">Square</span>();</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、文件拆分：通过三斜线指令引用当前目录文件。</span></span><br><span class="line"><span class="comment">// IPage.ts</span></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Page</span> &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">interface</span> <span class="title class_">IPage</span> &#123;</span><br><span class="line">        <span class="title function_">render</span>(<span class="attr">data</span>: <span class="built_in">object</span>): <span class="built_in">string</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// IndexPage.ts</span></span><br><span class="line"><span class="comment">/// &lt;reference path=&quot;./IPage.ts&quot; /&gt;</span></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Page</span> &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">class</span> <span class="title class_">IndexPage</span> <span class="keyword">implements</span> <span class="title class_">IPage</span> &#123;</span><br><span class="line">        <span class="title function_">render</span>(<span class="attr">data</span>: <span class="built_in">object</span>): <span class="built_in">string</span> &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">&#x27;&lt;div&gt;Index page content&lt;/div&gt;&#x27;</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// App.ts</span></span><br><span class="line"><span class="comment">/// &lt;reference path=&quot;./IndexPage.ts&quot; /&gt;</span></span><br><span class="line"><span class="comment">/// &lt;reference path=&quot;./DetailPage.ts&quot; /&gt;</span></span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> <span class="title class_">Page</span>.<span class="title class_">IndexPage</span>().<span class="title function_">render</span>(&#123;<span class="attr">value</span>: <span class="string">&#x27;index&#x27;</span>&#125;)</span><br></pre></td></tr></table></figure>


<h1 id="四、声明合并"><a href="#四、声明合并" class="headerlink" title="四、声明合并"></a>四、声明合并</h1><blockquote>
<p>编译器将多个地方具有相同名称的声明合并为一个，合并后的声明同时拥有所有原声明的特性。命名空间、类、枚举、接口、函数、变量等声明会创建出声明实体的一到三类，声明实体有 import 引入的<code>命名空间</code>、描述结构的 <code>type</code>、编译为 js 后唯一被保留的 <code>value</code>。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 1、同名接口合并</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 非函数成员：必须类型一致，否则就会报错。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 函数成员：声明在后的成员排序更靠前，参数类型为单一字符串的排名最靠前。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 以下注释为合并接口中的函数排序</span></span><br><span class="line"><span class="comment">**/</span> </span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">StateMerge</span> &#123;</span><br><span class="line">    <span class="attr">x</span>: <span class="built_in">number</span>,</span><br><span class="line">    <span class="attr">y</span>: <span class="built_in">string</span>,</span><br><span class="line">    <span class="title function_">foo</span>(<span class="attr">bar</span>: <span class="built_in">number</span>): <span class="built_in">number</span>;      <span class="comment">// 4</span></span><br><span class="line">    <span class="title function_">foo</span>(<span class="attr">bar</span>: <span class="built_in">string</span>): <span class="built_in">string</span>;      <span class="comment">// 5</span></span><br><span class="line">    <span class="title function_">foo</span>(<span class="attr">bar</span>: <span class="string">&quot;b&quot;</span>): <span class="built_in">number</span>;         <span class="comment">// 2</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">StateMerge</span> &#123;</span><br><span class="line">    <span class="attr">y</span>: <span class="built_in">string</span>;</span><br><span class="line">    <span class="title function_">foo</span>(<span class="attr">bar</span>: <span class="built_in">string</span>[]): <span class="built_in">string</span>[];  <span class="comment">// 3</span></span><br><span class="line">    <span class="title function_">foo</span>(<span class="attr">bar</span>: <span class="string">&quot;a&quot;</span>): <span class="built_in">number</span>          <span class="comment">// 1</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 2、同名的命名空间合并</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 同名的命名空间不能出现同名的变量和方法。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 合并后的命名空间成员无法访问非导出成员。 </span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Validation</span> &#123;</span><br><span class="line">    <span class="keyword">let</span> <span class="attr">name</span>: <span class="built_in">string</span> = <span class="string">&#x27;BNTang&#x27;</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Validation</span> &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">let</span> <span class="title function_">say</span> = (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">`<span class="subst">$&#123;name&#125;</span>`</span>);</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br><span class="line"><span class="title class_">Validation</span>.<span class="title function_">say</span>();  <span class="comment">// 报错：export let name 则正常</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 3、命名空间与类/函数/枚举：合并时将命名空间放到后面，扩展了属性和方法。</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span> &#123; &#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">Person</span>(<span class="params"></span>): <span class="built_in">string</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="title class_">Person</span>.<span class="property">name</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Person</span> &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">let</span> name = <span class="string">&#x27;Lishi&#x27;</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Person</span>.<span class="property">name</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Person</span>());</span><br><span class="line"></span><br><span class="line"><span class="keyword">enum</span> <span class="title class_">Gender</span> &#123; <span class="title class_">Male</span>, <span class="title class_">Female</span> &#125;</span><br><span class="line"><span class="keyword">namespace</span> <span class="title class_">Gender</span> &#123;</span><br><span class="line">    <span class="keyword">export</span> <span class="keyword">const</span> <span class="title class_">Yao</span>: <span class="built_in">number</span> = <span class="number">666</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="title class_">Gender</span>);</span><br></pre></td></tr></table></figure>


<h1 id="五、装饰器"><a href="#五、装饰器" class="headerlink" title="五、装饰器"></a>五、装饰器</h1><blockquote>
<p>一种可以附加到类、方法、属性或参数而扩展功能的特殊声明，本质是一个原代码外层包装了一层处理逻辑的函数并在 JS 编译时执行，比如对参数的类型判断、对返回值的排序过滤等。</p>
</blockquote>
<h2 id="实现方式"><a href="#实现方式" class="headerlink" title="实现方式"></a>实现方式</h2>  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// tsconfig.json：启用编译选项</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="string">&quot;compilerOptions&quot;</span>: &#123;</span><br><span class="line">    <span class="string">&quot;target&quot;</span>: <span class="string">&quot;ES5&quot;</span>,   <span class="comment">// 方法修饰器时需配置为 es6</span></span><br><span class="line">    <span class="string">&quot;experimentalDecorators&quot;</span>: <span class="literal">true</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 写法：无法传参的普通装饰器、可传参的装饰器工厂</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Person</span> &#123;</span><br><span class="line">    <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">    <span class="attr">age</span>: <span class="built_in">number</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">enhancer</span>(<span class="params">target: <span class="built_in">any</span></span>) &#123;</span><br><span class="line">    target.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">name</span> = <span class="string">&#x27;小白&#x27;</span></span><br><span class="line">    target.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">age</span> = <span class="number">18</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">@enhancer</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) &#123; &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">enhancer</span>(<span class="params">name: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">target: <span class="built_in">any</span></span>) &#123;</span><br><span class="line">        target.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">name</span> = name</span><br><span class="line">        target.<span class="property"><span class="keyword">prototype</span></span>.<span class="property">age</span> = <span class="number">18</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">@enhancer</span>(<span class="string">&#x27;小白&#x27;</span>)</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Person</span> &#123;</span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="主要分类"><a href="#主要分类" class="headerlink" title="主要分类"></a>主要分类</h2><blockquote>
<p>注意没有函数装饰器，不能使用在声明文件和任何外部上下文。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@title</span> 加载顺序</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 类装饰器总是最后执行。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 方法和属性：谁在前面谁先执行。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 方法和参数：参数装饰器会先执行。</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@param</span> 多个参数装饰器时：最后依次向前。</span></span><br><span class="line"><span class="comment">**/</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 1、类装饰器</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">decorateClass</span>(<span class="params">constructor</span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">class</span> <span class="title class_">B</span> <span class="keyword">extends</span> <span class="title class_ inherited__">constructor</span> &#123;</span><br><span class="line">        name = <span class="string">&#x27;A&#x27;</span>;</span><br><span class="line">        age = <span class="number">18</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">@decorateClass</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">A</span> &#123; &#125;</span><br><span class="line"><span class="keyword">const</span> a = <span class="keyword">new</span> <span class="title function_">A</span>();   <span class="comment">// &#123; name: &#x27;A&#x27;, age: 18 &#125;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">// 2、属性装饰器：target 对于静态成员是类的构造函数，对于实例成员是类的原型对象。</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">writableProperty</span>(<span class="params">flag: <span class="built_in">boolean</span></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">target: <span class="built_in">any</span>, prop: <span class="built_in">string</span> | <span class="built_in">symbol</span></span>) &#123;</span><br><span class="line">        <span class="title class_">Object</span>.<span class="title function_">defineProperty</span>(target, propName, &#123; <span class="attr">writable</span>: flag &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 3、方法装饰器</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">editableMethod</span>(<span class="params">flag: <span class="built_in">boolean</span></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">target:<span class="built_in">any</span>, method:<span class="built_in">string</span>, desp:PropertyDescriptor</span>)&#123;</span><br><span class="line">        descriptor.<span class="property">writable</span> = flag;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 4、参数装饰器</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">printArgs</span>(<span class="params">target: <span class="built_in">any</span>, param: <span class="built_in">string</span>, index: <span class="built_in">number</span></span>): <span class="built_in">void</span> &#123;</span><br><span class="line">  <span class="comment">// paramIndex 参数在函数参数列表中的索引</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(target, methodName, paramIndex);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 5、存取器装饰器：TS 不允许为单个成员装饰 get、set 访问器</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">configurable</span>(<span class="params">value: <span class="built_in">boolean</span></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">function</span> (<span class="params">target:<span class="built_in">any</span>, prop:<span class="built_in">string</span>, desp:PropertyDescriptor</span>) &#123;</span><br><span class="line">        descriptor.<span class="property">configurable</span> = value;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="meta">@addPropsAndMethods</span></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">DummyClass</span>&#123;</span><br><span class="line">    <span class="meta">@writableProperty</span>(<span class="literal">true</span>)</span><br><span class="line">    <span class="attr">name</span>: <span class="built_in">string</span>;</span><br><span class="line">    <span class="attr">bornY</span>: <span class="built_in">number</span>;</span><br><span class="line">    <span class="attr">_domain</span>: <span class="built_in">string</span>;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">constructor</span>(<span class="params">name: <span class="built_in">string</span>, bornY: <span class="built_in">number</span></span>) &#123;</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            <span class="variable language_">this</span>.<span class="property">name</span> = name;</span><br><span class="line">        &#125; <span class="keyword">catch</span>(e) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Error:&#x27;</span>,e);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">bornY</span> = bornY;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="title function_">printData</span>(<span class="params">prefix: <span class="built_in">string</span>, <span class="meta">@printArgs</span> printAll: <span class="built_in">boolean</span></span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (printAll) &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span> + <span class="variable language_">this</span>.<span class="property">bornY</span>);</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="variable language_">this</span>.<span class="property">name</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 不允许修改该方法</span></span><br><span class="line">    <span class="meta">@editableMethod</span>(<span class="literal">false</span>)</span><br><span class="line">    <span class="title function_">dummyMethod</span>(<span class="params"></span>)&#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Hi&#x27;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 存取器装饰器</span></span><br><span class="line">    <span class="meta">@configurable</span>(<span class="literal">false</span>)</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">data</span>() &#123; <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">name</span> + <span class="string">&#x27;@&#x27;</span> + <span class="variable language_">this</span>.<span class="property">bornY</span>; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@configurable</span>(<span class="literal">false</span>)</span><br><span class="line">    <span class="keyword">set</span> <span class="title function_">domain</span>(<span class="params">value: <span class="built_in">string</span></span>) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">_domain</span> = value;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">get</span> <span class="title function_">domain</span>(): <span class="built_in">string</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="variable language_">this</span>.<span class="property">_domain</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> d = <span class="keyword">new</span> <span class="title class_">DummyClass</span>(<span class="string">&quot;Jack Ma&quot;</span>, <span class="number">1981</span>);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;类的装饰器：为类添加方法、属性和默认属性值&#x27;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>((&lt;<span class="built_in">any</span>&gt;d).<span class="title function_">helloWorld</span>());</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;属性的装饰器)&#x27;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;方法的装饰器：让方法不可被修改，下面的修改无效&#x27;</span>);</span><br><span class="line">d.<span class="title function_">dummyMethod</span>();</span><br><span class="line">d.<span class="property">dummyMethod</span> = <span class="keyword">function</span>(<span class="params"></span>)&#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;Hi there!&#x27;</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">d.<span class="title function_">dummyMethod</span>();</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&#x27;存取器装饰器&#x27;</span>);</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(d.<span class="property">data</span>);</span><br><span class="line"></span><br><span class="line">d.<span class="property">domain</span> = <span class="string">&quot;coolwp.com&quot;</span>;</span><br><span class="line"><span class="variable language_">console</span>.<span class="title function_">log</span>(d.<span class="property">domain</span>);</span><br></pre></td></tr></table></figure>


<h1 id="六、JSX"><a href="#六、JSX" class="headerlink" title="六、JSX"></a>六、JSX</h1><blockquote>
<p>全称 <code>JavaScript XML</code>，React 发明的一种类似 XML 的 JS 扩展语法，主要用于创建虚拟 DOM 并可以编译为 JS 对象，编译的基本规则为：<code>&lt; 开头的代码以 HTML 语法解析、&#123; 开头的代码以 JS 语法解析</code>。TS 支持嵌入、类型检查和直接编译 JSX 为有效的 JS。</p>
</blockquote>
<h2 id="基础使用"><a href="#基础使用" class="headerlink" title="基础使用"></a>基础使用</h2><ul>
<li><strong>使用前提</strong>：使用 tsx 文件、启用 jsx 选项。</li>
<li><strong>类型断言</strong>：tsx 文件中的类型断言必须使用 as 操作符，因为使用尖括号表示类型断言时结合 JSX 语法后将带来解析上的困难。</li>
<li><strong>编译模式</strong>：仅影响编译阶段，类型检查不受影响。可以通过在命令行使用 <code>--jsx</code> 标记或者在 <code>tscofnig.json</code> 文件中指定选项。<ul>
<li><strong>preserve</strong>：将保持 JSX 作为部分输出以用于 Babel 等变换时编译。输出 .jsx 文件。</li>
<li><strong>react</strong>：调用 <code>React.createElement</code> 而不需要经过 JSX 转换，输出 .js 文件。 </li>
<li><strong>react-native</strong>：相当于保留，因为它保留了所有 JSX。输出 .js 文件。</li>
</ul>
</li>
<li><strong>结果类型</strong>：默认是 any 类型，可以通过指定 <code>JSX.Element</code> 接口实现自定义类型，但是不能从接口里检索元素、属性或子元素的类型信息。</li>
</ul>
<h2 id="类型检查"><a href="#类型检查" class="headerlink" title="类型检查"></a>类型检查</h2><blockquote>
<p>假设有一个 JSX 表达式 <code>&lt;expr /&gt;</code>，expr 可能是固有元素(环境自带的东西，比如 DOM 环境的 div、span)，也可能是基于值的元素(自定义组件)。TS 使用与 React 相同的规范来区别它们：<code>固有元素总是以一个小写字母开头，基于值的元素总是以一个大写字母开头</code>。</p>
</blockquote>
<h3 id="固有元素"><a href="#固有元素" class="headerlink" title="固有元素"></a>固有元素</h3><blockquote>
<p>使用特殊接口 JSX.IntrinsicElements 来查找。如果这个接口没有指定，则不对固有元素进行类型检查而全部通过。如果接口存在，则固有元素的名字需要在接口的属性里查找。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 没有 JSX.IntrinsicElements 里指定的就会报错。</span></span><br><span class="line"><span class="keyword">declare</span> <span class="keyword">namespace</span> JSX　&#123;</span><br><span class="line">    <span class="keyword">interface</span> <span class="title class_">IntrinsicElements</span> &#123;</span><br><span class="line">        <span class="attr">foo</span>: <span class="built_in">any</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;foo /&gt;    <span class="comment">// 正确</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">bar</span> /&gt;</span></span>    <span class="comment">// 报错</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 指定一个用来捕获所有字符串索引</span></span><br><span class="line">declate <span class="keyword">namespace</span> JSX &#123;</span><br><span class="line">    <span class="keyword">interface</span> <span class="title class_">IntrinsicElements</span> &#123;</span><br><span class="line">        [<span class="attr">elemName</span>: <span class="built_in">string</span>]: <span class="built_in">any</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h3 id="基于值的元素"><a href="#基于值的元素" class="headerlink" title="基于值的元素"></a>基于值的元素</h3><blockquote>
<p>在它所在的作用域里按照标识符查找。它有两种定义方式：<strong>无状态函数组件 SFC、类组件</strong>，由于它们在 JSX 表达式里无法区分，TS 解析时会先将表达式作为无状态函数组件，解析成功则完成操作，否则以类组件的形式进行解析，依旧失败则抛出错误。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">MyCom</span> <span class="keyword">from</span> <span class="string">&#x27;./myCom&#x27;</span>;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">MyCom</span> /&gt;</span></span>         <span class="comment">// 正确</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">OtherCom</span> /&gt;</span></span>      <span class="comment">// 报错</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 无状态函数组件：返回值可以赋值给 JSX.Element</span></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">FooProp</span> &#123;</span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span>;</span><br><span class="line">  <span class="attr">X</span>: <span class="built_in">number</span>;</span><br><span class="line">  <span class="attr">Y</span>: <span class="built_in">number</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">declare</span> <span class="keyword">function</span> <span class="title function_">AnotherCom</span>(<span class="params">prop: &#123;name: <span class="built_in">string</span>&#125;</span>);  <span class="comment">// declare 声明文件或模块</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">ComFoo</span>(<span class="params">prop: FooProp</span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">AnotherCom</span> <span class="attr">name</span>=<span class="string">&#123;prop.name&#125;</span> /&gt;</span></span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> <span class="title function_">Button</span> = (<span class="params">prop: &#123;value: <span class="built_in">string</span>&#125;, context: &#123;color: <span class="built_in">string</span>&#125;</span>) =&gt; &lt;button&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 类组件：元素的实例类型必须赋值给 JSX.ElementClass，否则抛出错误。</span></span><br><span class="line"><span class="comment">// 元素类的类型：MyComponent、MyFactoryFn</span></span><br><span class="line"><span class="comment">// 元素实例的类型： &#123; render: () =&gt; void &#125;</span></span><br><span class="line"><span class="keyword">declare</span> <span class="keyword">namespace</span> JSX &#123;</span><br><span class="line">  <span class="keyword">interface</span> <span class="title class_">ElementClass</span> &#123;</span><br><span class="line">    <span class="attr">render</span>: <span class="built_in">any</span>;  <span class="comment">// 如果没有 render 方法则会报错。</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyComponent</span> &#123;</span><br><span class="line">  <span class="title function_">render</span>(<span class="params"></span>) &#123;&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">function</span> <span class="title function_">MyFactoryFn</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123; <span class="attr">render</span>: <span class="function">() =&gt;</span> &#123;&#125; &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;<span class="title class_">MyComponent</span> /&gt;;    <span class="comment">// 正确</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">MyFactoryFn</span> /&gt;</span></span>;    <span class="comment">// 正确</span></span><br></pre></td></tr></table></figure>


<h3 id="属性类型检查"><a href="#属性类型检查" class="headerlink" title="属性类型检查"></a>属性类型检查</h3><ol>
<li>确定元素属性类型<br>* 固有元素：JSX.IntrinsicElements 接口中的属性类型。<br>* 基于值的元素：元素实例类型上的 JSX.ElementAttributesProperty 指定属性的类型，没有指定则使用类元素构造函数或 SFC 调用的第一个参数的类型。</li>
<li>JSX 里进行属性检查<br>* 支持可选属性、必选属性。<br>* 如果一个属性名不是个合法的 JS 标识符(比如 data-* 属性)，并且它没有出现在元素属性类型里时不会报错。<br><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 固有元素 foo：&#123;bar?: boolean&#125;</span></span><br><span class="line"><span class="keyword">declare</span> <span class="keyword">namespace</span> JSX &#123;</span><br><span class="line">  <span class="keyword">interface</span> <span class="title class_">IntrinsicElements</span> &#123;</span><br><span class="line">    <span class="attr">foo</span>: &#123;</span><br><span class="line">      <span class="attr">required</span>: <span class="built_in">string</span>; </span><br><span class="line">      bar?: <span class="built_in">boolean</span> </span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;foo required=<span class="string">&quot;a&quot;</span> /&gt;;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">foo</span> <span class="attr">required</span>=<span class="string">&quot;a&quot;</span> <span class="attr">bar</span> /&gt;</span></span>;</span><br><span class="line"><span class="comment">// 正确：some-unknown 不是合法的标识符</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">foo</span> <span class="attr">required</span>=<span class="string">&quot;a&quot;</span> <span class="attr">some-unknown</span> /&gt;</span></span>;</span><br><span class="line"><span class="comment">// 报错：缺少必须属性、unknown 不存在</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">foo</span> /&gt;</span></span>;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">foo</span> <span class="attr">required</span>=<span class="string">&quot;a&quot;</span> <span class="attr">unknown</span> /&gt;</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 基于值的元素 MyCom：&#123;foo?: string&#125;</span></span><br><span class="line"><span class="keyword">declare</span> <span class="keyword">namespace</span> JSX &#123;</span><br><span class="line">  <span class="keyword">interface</span> <span class="title class_">ElementAttributesProperty</span> &#123;</span><br><span class="line">    props;     <span class="comment">// 指定属性名</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyCom</span> &#123;</span><br><span class="line">  <span class="attr">props</span>: &#123;  <span class="comment">// 在元素实例类型上指定属性</span></span><br><span class="line">    foo?: <span class="built_in">string</span>;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;<span class="title class_">MyCom</span> foo=<span class="string">&quot;bar&quot;</span> /&gt;</span><br></pre></td></tr></table></figure></li>
</ol>
<h3 id="子孙类型检查"><a href="#子孙类型检查" class="headerlink" title="子孙类型检查"></a>子孙类型检查</h3>  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">interface</span> <span class="title class_">PropsType</span> &#123;</span><br><span class="line">  <span class="attr">children</span>: <span class="variable constant_">JSX</span>.<span class="property">Element</span></span><br><span class="line">  <span class="attr">name</span>: <span class="built_in">string</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">class</span> <span class="title class_">Component</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span>&lt;<span class="title class_">PropsType</span>, &#123;&#125;&gt; &#123;</span><br><span class="line">  <span class="title function_">render</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> (</span><br><span class="line">      <span class="language-xml"><span class="tag">&lt;<span class="name">h2</span>&gt;</span>&#123;this.props.children&#125;<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span></span><br><span class="line">    )</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 正确</span></span><br><span class="line">&lt;<span class="title class_">Component</span>&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>Hello World<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span></span><br><span class="line">&lt;/<span class="title class_">Component</span>&gt;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 报错：JSX.Element 不是数组类型</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">Component</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">h1</span>&gt;</span>Hello World<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">h2</span>&gt;</span>Hello World<span class="tag">&lt;/<span class="name">h2</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">Component</span>&gt;</span></span></span><br></pre></td></tr></table></figure>


<h2 id="React-集成"><a href="#React-集成" class="headerlink" title="React 集成"></a>React 集成</h2>  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 使用 React 类型定义</span></span><br><span class="line"><span class="comment">/// &lt;reference path=&quot;react.d.ts&quot; /&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">interface</span> <span class="title class_">Props</span> &#123;</span><br><span class="line">  <span class="attr">foo</span>: <span class="built_in">string</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">MyCom</span> <span class="keyword">extends</span> <span class="title class_ inherited__">React.Component</span>&lt;<span class="title class_">Props</span>, &#123;&#125;&gt; &#123;</span><br><span class="line">  <span class="title function_">render</span>(<span class="params"></span>) &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="language-xml"><span class="tag">&lt;<span class="name">span</span>&gt;</span>&#123;this.props.foo&#125;<span class="tag">&lt;/<span class="name">span</span>&gt;</span></span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 正确</span></span><br><span class="line">&lt;<span class="title class_">MyCom</span> foo=<span class="string">&quot;bar&quot;</span> /&gt;; </span><br><span class="line"><span class="comment">// 报错</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">MyComponent</span> <span class="attr">foo</span>=<span class="string">&#123;0&#125;</span> /&gt;</span></span>; </span><br></pre></td></tr></table></figure>


<h2 id="工厂函数"><a href="#工厂函数" class="headerlink" title="工厂函数"></a>工厂函数</h2><blockquote>
<p><code>jsx: react</code> 编译选项用的工厂函数是可以配置的。可以使用 <code>jsxFactory</code> 命令行选项，或者内联的 <code>@jsx</code> 注释指令在每个文件上设置。</p>
</blockquote>
  <figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 设置 jsxFactory：调用 createElement(&quot;div&quot;) 而非 React.createElement(&quot;div&quot;)</span></span><br><span class="line"><span class="keyword">import</span> preact = <span class="built_in">require</span>(<span class="string">&quot;preact&quot;</span>);</span><br><span class="line"><span class="comment">/* @jsx preact.h */</span></span><br><span class="line"><span class="keyword">const</span> x = <span class="language-xml"><span class="tag">&lt;<span class="name">div</span> /&gt;</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 结果</span></span><br><span class="line"><span class="keyword">const</span> preact = <span class="built_in">require</span>(<span class="string">&#x27;preact&#x27;</span>);</span><br><span class="line"><span class="keyword">const</span> x =  preact.<span class="title function_">h</span>(<span class="string">&quot;div&quot;</span>, <span class="literal">null</span>);</span><br></pre></td></tr></table></figure>



    </div>

    
    
    <div>
      
        <div>
    
        <div style="text-align:center;color: #ccc;font-size:14px;margin-top:20px;">-------------本文结束<i class="fa fa-paw"></i>感谢您的阅读-------------</div>
    
</div>

      
    </div>
    
        

<div>
<ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者： </strong>chuangges
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="https://chuangges.gitee.io/2019/11/06/11-2-typescript%20%E8%BF%9B%E9%98%B6%E8%AF%AD%E6%B3%95/" title="TypeScript 进阶语法">https://chuangges.gitee.io/2019/11/06/11-2-typescript 进阶语法/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/zh_CN" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-fw fa-creative-commons"></i>BY-NC-SA</a> 许可协议。转载请注明出处！
  </li>
</ul>
</div>


      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2019/11/03/11-1-typescript%20%E6%95%B0%E6%8D%AE%E7%B1%BB%E5%9E%8B/" rel="prev" title="TypeScript 入门">
      <i class="fa fa-chevron-left"></i> TypeScript 入门
    </a></div>
      <div class="post-nav-item">
    <a href="/2020/03/22/12-%E9%9D%A2%E8%AF%95%E9%A2%98%E4%B9%8B%E5%9F%BA%E7%A1%80%E7%AF%87/" rel="next" title="面试题之基础篇">
      面试题之基础篇 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%80%E3%80%81%E7%B1%BB%E5%9E%8B%E6%A3%80%E6%9F%A5"><span class="nav-number">1.</span> <span class="nav-text">一、类型检查</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E7%BA%A6%E6%9D%9F"><span class="nav-number">1.1.</span> <span class="nav-text">类型约束</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E6%96%AD%E8%A8%80"><span class="nav-number">1.2.</span> <span class="nav-text">类型断言</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E6%8E%A8%E6%96%AD"><span class="nav-number">1.3.</span> <span class="nav-text">类型推断</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E5%85%BC%E5%AE%B9"><span class="nav-number">1.4.</span> <span class="nav-text">类型兼容</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E4%BF%9D%E6%8A%A4"><span class="nav-number">1.5.</span> <span class="nav-text">类型保护</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E5%88%AB%E5%90%8D"><span class="nav-number">1.6.</span> <span class="nav-text">类型别名</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%8C%E3%80%81%E9%AB%98%E7%BA%A7%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.</span> <span class="nav-text">二、高级类型</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%BA%A4%E5%8F%89%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.1.</span> <span class="nav-text">交叉类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E8%81%94%E5%90%88%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.2.</span> <span class="nav-text">联合类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B4%A2%E5%BC%95%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.3.</span> <span class="nav-text">索引类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%98%A0%E5%B0%84%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.4.</span> <span class="nav-text">映射类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E6%9D%A1%E4%BB%B6%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.5.</span> <span class="nav-text">条件类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AF%E4%B8%BA-null-%E7%9A%84%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.6.</span> <span class="nav-text">可为 null 的类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AD%97%E9%9D%A2%E9%87%8F%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.7.</span> <span class="nav-text">字面量类型</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%8F%AF%E8%BE%A8%E8%AF%86%E8%81%94%E5%90%88"><span class="nav-number">2.8.</span> <span class="nav-text">可辨识联合</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%A4%9A%E6%80%81%E7%9A%84-this-%E7%B1%BB%E5%9E%8B"><span class="nav-number">2.9.</span> <span class="nav-text">多态的 this 类型</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%B8%89%E3%80%81%E5%91%BD%E5%90%8D%E7%A9%BA%E9%97%B4"><span class="nav-number">3.</span> <span class="nav-text">三、命名空间</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%9B%9B%E3%80%81%E5%A3%B0%E6%98%8E%E5%90%88%E5%B9%B6"><span class="nav-number">4.</span> <span class="nav-text">四、声明合并</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E4%BA%94%E3%80%81%E8%A3%85%E9%A5%B0%E5%99%A8"><span class="nav-number">5.</span> <span class="nav-text">五、装饰器</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F"><span class="nav-number">5.1.</span> <span class="nav-text">实现方式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E4%B8%BB%E8%A6%81%E5%88%86%E7%B1%BB"><span class="nav-number">5.2.</span> <span class="nav-text">主要分类</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#%E5%85%AD%E3%80%81JSX"><span class="nav-number">6.</span> <span class="nav-text">六、JSX</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%9F%BA%E7%A1%80%E4%BD%BF%E7%94%A8"><span class="nav-number">6.1.</span> <span class="nav-text">基础使用</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E7%B1%BB%E5%9E%8B%E6%A3%80%E6%9F%A5"><span class="nav-number">6.2.</span> <span class="nav-text">类型检查</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%9B%BA%E6%9C%89%E5%85%83%E7%B4%A0"><span class="nav-number">6.2.1.</span> <span class="nav-text">固有元素</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%9F%BA%E4%BA%8E%E5%80%BC%E7%9A%84%E5%85%83%E7%B4%A0"><span class="nav-number">6.2.2.</span> <span class="nav-text">基于值的元素</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%B1%9E%E6%80%A7%E7%B1%BB%E5%9E%8B%E6%A3%80%E6%9F%A5"><span class="nav-number">6.2.3.</span> <span class="nav-text">属性类型检查</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%AD%90%E5%AD%99%E7%B1%BB%E5%9E%8B%E6%A3%80%E6%9F%A5"><span class="nav-number">6.2.4.</span> <span class="nav-text">子孙类型检查</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#React-%E9%9B%86%E6%88%90"><span class="nav-number">6.3.</span> <span class="nav-text">React 集成</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#%E5%B7%A5%E5%8E%82%E5%87%BD%E6%95%B0"><span class="nav-number">6.4.</span> <span class="nav-text">工厂函数</span></a></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="chuangges" src="" data-original="/images/chuang.png">
  <p class="site-author-name" itemprop="name">chuangges</p>
  <div class="site-description" itemprop="description">chuangge's blog.</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">39</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">7</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="https://github.com/chuangges" title="GitHub → https:&#x2F;&#x2F;github.com&#x2F;chuangges" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-github fa-fw"></i>GitHub</a>
      </span>
      <span class="links-of-author-item">
        <a href="https://stackoverflow.com/yourname" title="StackOverflow → https:&#x2F;&#x2F;stackoverflow.com&#x2F;yourname" rel="external nofollow noopener noreferrer" target="_blank"><i class="fab fa-stack-overflow fa-fw"></i>StackOverflow</a>
      </span>
  </div>


  <div class="links-of-blogroll motion-element">
    <div class="links-of-blogroll-title"><i class="fa fa-link fa-fw"></i>
      友情链接
    </div>
    <ul class="links-of-blogroll-list">
        <li class="links-of-blogroll-item">
          <a href="https://juejin.im/" title="https:&#x2F;&#x2F;juejin.im&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">掘金</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://www.nowcoder.com/" title="https:&#x2F;&#x2F;www.nowcoder.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">牛客网</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://www.docschina.org/" title="https:&#x2F;&#x2F;www.docschina.org&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">印记中文</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="http://tool.lu/" title="http:&#x2F;&#x2F;tool.lu&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">在线工具</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://tinypng.com/" title="https:&#x2F;&#x2F;tinypng.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">图片压缩</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://bigjpg.com/" title="https:&#x2F;&#x2F;bigjpg.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">图片放大</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://tool.chinaz.com/" title="https:&#x2F;&#x2F;tool.chinaz.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">站长工具</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://learn-anything.xyz/" title="https:&#x2F;&#x2F;learn-anything.xyz&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">Learn-Anything</a>
        </li>
        <li class="links-of-blogroll-item">
          <a href="https://stackoverflow.com/" title="https:&#x2F;&#x2F;stackoverflow.com&#x2F;" rel="external nofollow noopener noreferrer" target="_blank">Stack-Overflow</a>
        </li>
    </ul>
  </div>

      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2024</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">chuangge</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-chart-area"></i>
    </span>
    <span title="站点总字数">1m</span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-coffee"></i>
    </span>
    <span title="站点阅读时长">15:14</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="external nofollow noopener noreferrer" target="_blank">Hexo</a> & <a href="https://pisces.theme-next.org/" class="theme-link" rel="external nofollow noopener noreferrer" target="_blank">NexT.Pisces</a> 强力驱动
  </div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","model":{"jsonPath":"/live2dw/assets/tororo.model.json"},"display":{"position":"left","width":180,"height":360},"mobile":{"show":false},"react":{"opacityDefault":1,"opacityOnHover":1},"log":false,"tagMode":false});</script>
        <style>
            [bg-lazy] {
                background-image: none !important;
                background-color: #eee !important;
            }
        </style>
        <script>
            window.imageLazyLoadSetting = {
                isSPA: false,
                preloadRatio: 1,
                processImages: null,
            };
        </script><script>window.addEventListener("load",function(){var t=/\.(gif|jpg|jpeg|tiff|png)$/i,r=/^data:image\/[a-z]+;base64,/;Array.prototype.slice.call(document.querySelectorAll("img[data-original]")).forEach(function(a){var e=a.parentNode;"A"===e.tagName&&(e.href.match(t)||e.href.match(r))&&(e.href=a.dataset.original)})});</script><script>!function(e){e.imageLazyLoadSetting.processImages=t;var n=e.imageLazyLoadSetting.isSPA,i=e.imageLazyLoadSetting.preloadRatio||1,r=o();function o(){var t=Array.prototype.slice.call(document.querySelectorAll("img[data-original]")),e=Array.prototype.slice.call(document.querySelectorAll("[bg-lazy]"));return t.concat(e)}function t(){n&&(r=o());for(var t,a=0;a<r.length;a++)0<=(t=(t=r[a]).getBoundingClientRect()).bottom&&0<=t.left&&t.top<=(e.innerHeight*i||document.documentElement.clientHeight*i)&&function(){var t,e,n,i,o=r[a];e=function(){r=r.filter(function(t){return o!==t})},(t=o).hasAttribute("bg-lazy")?(t.removeAttribute("bg-lazy"),e&&e()):(n=new Image,i=t.getAttribute("data-original"),n.onload=function(){t.src=i,t.removeAttribute("data-original"),e&&e()},t.src!==i&&(n.src=i))}()}function a(){clearTimeout(t.tId),t.tId=setTimeout(t,500)}t(),document.addEventListener("scroll",a),e.addEventListener("resize",a),e.addEventListener("orientationchange",a)}(this);</script></body>
</html>
